#include "include/string.h"

uint8_t bit_to_one[8] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }; // use `|`
uint8_t bit_to_zero[8] = { 0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f }; // use `&`

/**
 * Set memory in bit
 * 
 * @param s source address
 * @param n the nth bit to be set
 * @param c value to be set: only 0 or 1
 * @return source address
 */
void* membitset(void *s, uint32_t n, uint8_t c) {
  uint32_t num_bytes = n >> 3; // divide by 8B to calculate the number of bytes
  uint8_t num_bits = n & 0x7; // divide by 8B to take the remainder, calculate the number of bits in 1 byte

  uint8_t *tmp = s;
  tmp += num_bytes; // Pointing to the nth byte
  if (c == 1) {
    *tmp = (*tmp) | bit_to_one[num_bits];
  } else if (c == 0) {
    *tmp = (*tmp) & bit_to_zero[num_bits];
  }

  return s;
}

/**
 * Get memory in bit
 * 
 * @param s source address
 * @param n the nth bit to be set
 * @return byte where nth bit is located
 */
uint8_t membitget(void *s, uint32_t n) {
  uint32_t num_bytes = n >> 3; // divide by 8B to calculate the number of bytes
  uint8_t num_bits = n & 0x7; // divide by 8B to take the remainder, calculate the number of bits in 1 byte

  uint8_t *tmp = s;
  tmp += num_bytes; // Pointing to the nth byte

  return (*tmp) & bit_to_one[num_bits];
}

/**
 * Set memory in bytes
 * 
 * @param s source address
 * @param c value to be set
 * @param n num bytes to be set
 * @return source address
 */
void* memset(void *s, uint8_t c, uint32_t n) {
  uint8_t *tmp = s;

  while (n--) {
    *tmp++ = c;
  }

  return s;
}

/**
 * Copy memory from one to one
 * 
 * @param dest destination address
 * @param src source address
 * @param n num bytes to be copy
 */
void memcpy(void *dest, const void *src, int n) {
  char *tmp = dest;
  const char *s = src;
  
  while (n--) {
    *tmp++ = *s++;
  }
}

/**
 * Compare two strings
 * 
 * @param s1
 * @param s2
 * @return -1 | 0 | 1
 */
int strcmp(const char *s1, const char *s2) {
  while (1) {
    if (*s1 != *s2) {
      return *s1 > *s2 ? 1 : -1;
    }
    if (!*s1) { // Judging the end of a string with '\0'
      break;
    }
    s1++;
    s2++;
  }
  return 0;
}

/**
 * Calculate the byte length of a string
 * 
 * @param s
 * @return byte length
 */
int strlen(const char *s) {
  const char* tmp = s;
  while (*tmp != '\0') {
    tmp++;
  }
  return tmp - s;
}